﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using YZH.Audio.Disting;
namespace YZH.Audio.Disting
{
    
    /// <summary>
    ///语义识别驱动
    /// 作    者：叶志辉
    /// 创建时间：
    /// 修改时间：
    ///</summary>  
    public class VoiceDistingDriver:IDisposable
    {
        #region 字段
        IntPtr _baseHandler;
        IntPtr _sessionHandler;
        #endregion

        #region 事件
        public delegate void OnMessageHandler(object obj,string msg);
        public OnMessageHandler OnMessage;
        private void RaiseOnMessage(object obj,string msg)
        {
            var tmp = OnMessage;
            try
            {
                if (tmp != null)
                    tmp(obj, msg);
            }
            catch { }
        }
        #endregion

        #region 初始化接口
        public VoiceDistingDriver()
        {
            Init("recog_dnn_adult.ini");            
        }

        public VoiceDistingDriver(string infFile)
        {
            Init(infFile);
        }

        private void Init(string fileName)
        {
            int result = VoiceDistingAPI.recognizer_createBase(out _baseHandler, fileName);
            if(result<0)
            {
                throw new Exception("创建识别驱动失败，错误号"+result.ToString());
            }
            
            result = VoiceDistingAPI.recognizer_createSession(out _sessionHandler, _baseHandler, "");
            if(result<0)
            {
                throw new Exception("创建识别会话失败，错误号"+result.ToString());
            }
            result = VoiceDistingAPI.recognizer_startSession(_sessionHandler,1);
            if (result < 0)
            {
                throw new Exception("启动识别绘画失败，错误号" + result.ToString());
            }
        }

        public void SendData(byte[] data)
        {            
            int code=0;

            int len1 = data.Length / 2;
            if (len1 <= 0) return;
            /*
            MemoryStream mem = new MemoryStream(data);
            BinaryReader reader = new BinaryReader(mem);
            short[] buf = new short[len1];
            for(int i=0;i<len1;i++)
            {
                buf[i]=reader.ReadInt16();
            }
            mem.Close();
            */
            int seglen = 3200;
            int  feedlen;
            int secIndex=0;
            StringBuilder builder = new StringBuilder();
            byte[] realbuf = new byte[seglen * 2];
            var bufHandler= GCHandle.Alloc(realbuf, GCHandleType.Pinned);
            var bufIntptr= bufHandler.AddrOfPinnedObject();
            /*
            byte[] msgBuf=new byte[2000];
            var msgHandler = GCHandle.Alloc(msgBuf, GCHandleType.Pinned);
            var msgIntptr = msgHandler.AddrOfPinnedObject();*/
            IntPtr resAddr;
            while (len1 > 0)
            {
                feedlen = len1 < seglen ? len1 : seglen;
                Array.Copy(data, secIndex * seglen*2, realbuf, 0, feedlen*2);
                
                code = VoiceDistingAPI.recognizer_resumeSession(_sessionHandler, bufIntptr, (uint)feedlen);
                secIndex++;
                len1 -= seglen;
                //printf("recognzier_resumeSession code = %d, time = %d\n", code, (UInt32) (getCurrentMs() - st));
                
                if (code > 0)
                {
                    code=VoiceDistingAPI.recognizer_getSessionRes(_sessionHandler, out resAddr);

                    VoiceDistingAPI.DecResult rec=(VoiceDistingAPI.DecResult)Marshal.PtrToStructure(resAddr, typeof(VoiceDistingAPI.DecResult));
                    if (rec.NSentence <= 0)
                    {
                        VoiceDistingAPI.recognizer_releaseSessionRes(resAddr);
                        continue;
                    }
                    string msg = GetStringFromStruct(rec);
                    if(string.IsNullOrEmpty(msg)==false)
                    {
                        RaiseOnMessage(this, msg);
                    }
                    VoiceDistingAPI.recognizer_releaseSessionRes(resAddr);

                    /*
                    VoiceDistingAPI.recognizer_resumeSession(_sessionHandler, msgIntptr, 2000);
                    byte[] tmp=(byte[])msgHandler.Target;
                     */
                }
            }
            if (bufHandler.IsAllocated)
                bufHandler.Free();
            /*
            if (msgHandler.IsAllocated)
                msgHandler.Free();*/
        }

        public void CreateSession()
        {
            VoiceDistingAPI.recognizer_stopSession(_sessionHandler);
            VoiceDistingAPI.recognizer_destroySession(_sessionHandler);
            var result = VoiceDistingAPI.recognizer_createSession(out _sessionHandler, _baseHandler, "");
            if (result < 0)
            {
                _sessionHandler=IntPtr.Zero;
                throw new Exception("err.createsession");
            }
            result = VoiceDistingAPI.recognizer_startSession(_sessionHandler, 1);
            if (result < 0)
            {
                _sessionHandler = IntPtr.Zero;
                throw new Exception("err.createsession");
            }
        }

        public string GetMessage(byte[]data)
        {
            int code = 0;
            if (_sessionHandler == IntPtr.Zero)
            {
                throw new Exception("err.createsession");
            }
            int len1 = data.Length / 2;
            if (len1 <= 0) return"";
            /*
            MemoryStream mem = new MemoryStream(data);
            BinaryReader reader = new BinaryReader(mem);
            short[] buf = new short[len1];
            for(int i=0;i<len1;i++)
            {
                buf[i]=reader.ReadInt16();
            }
            mem.Close();
            */
            int seglen = 3200;
            int feedlen;
            int secIndex = 0;
            StringBuilder builder = new StringBuilder();
            byte[] realbuf = new byte[seglen * 2];
            var bufHandler = GCHandle.Alloc(realbuf, GCHandleType.Pinned);
            var bufIntptr = bufHandler.AddrOfPinnedObject();
            /*
            byte[] msgBuf=new byte[2000];
            var msgHandler = GCHandle.Alloc(msgBuf, GCHandleType.Pinned);
            var msgIntptr = msgHandler.AddrOfPinnedObject();*/
            IntPtr resAddr;

            while (len1 > 0)
            {
                feedlen = len1 < seglen ? len1 : seglen;
                Array.Copy(data, secIndex * seglen * 2, realbuf, 0, feedlen * 2);

                code = VoiceDistingAPI.recognizer_resumeSession(_sessionHandler, bufIntptr, (uint)feedlen);
                secIndex++;
                len1 -= seglen;
                //printf("recognzier_resumeSession code = %d, time = %d\n", code, (UInt32) (getCurrentMs() - st));

                if (code > 0)
                {
                    code = VoiceDistingAPI.recognizer_getSessionRes(_sessionHandler, out resAddr);

                    VoiceDistingAPI.DecResult rec = (VoiceDistingAPI.DecResult)Marshal.PtrToStructure(resAddr, typeof(VoiceDistingAPI.DecResult));
                    if (rec.NSentence <= 0) continue;
                    string msg = GetStringFromStruct(rec);
                    if (string.IsNullOrEmpty(msg) == false)
                    {
                        builder.Append(msg);
                    }
                    VoiceDistingAPI.recognizer_releaseSessionRes(resAddr);

                    /*
                    VoiceDistingAPI.recognizer_resumeSession(_sessionHandler, msgIntptr, 2000);
                    byte[] tmp=(byte[])msgHandler.Target;
                     */
                }
                else if (code<0)
                {
                    CreateSession();
                }
            }
            if (bufHandler.IsAllocated)
                bufHandler.Free();
            return builder.ToString();
        }

        private string GetStringFromStruct(VoiceDistingAPI.DecResult rec)
        {
            IntPtr sentenceAddr = rec.PSentence;

            StringBuilder builder = new StringBuilder();

            for (int i = 0; i < rec.NSentence; i++)
            {
                VoiceDistingAPI.DecSentence ses = (VoiceDistingAPI.DecSentence)Marshal.PtrToStructure(sentenceAddr, typeof(VoiceDistingAPI.DecSentence));

                if (ses.NWords <= 0) continue;

                IntPtr wordContent = Marshal.ReadIntPtr(ses.Word);
                IntPtr wordAdress= ses.Word;
                byte[] bbuf = new byte[30];
                for (int k = 0; k < ses.NWords; k++)
                {
                    Marshal.Copy(wordContent, bbuf, 0, 30);
                    string sss = GetStringFromBytes(bbuf);
                    builder.Append(sss);
                    wordAdress = IntPtr.Add(wordAdress, 4);
                    wordContent = Marshal.ReadIntPtr(wordAdress);
                }
                sentenceAddr = IntPtr.Add(sentenceAddr, IntPtr.Size);
            }
            return builder.ToString();
        }
        private string GetStringFromBytes(byte[] data)
        {            
            //去掉空白
            int index = -1;
            for (int i = 0; i < data.Length; i++)
            {
                if (data[i] == 0)
                {
                    index = i;
                    break;
                }
            }
            if (index == -1)
                index = data.Length;
            if (index <= 0) return "";

            byte[] realdata=new byte[index];
            Array.Copy(data, realdata, index);
            return Encoding.UTF8.GetString(realdata);
        }
        ~VoiceDistingDriver()
        {
            Dispose();
        }
        public void Dispose()
        {            
            if(_sessionHandler!=IntPtr.Zero)
            {
                try
                {
                    VoiceDistingAPI.recognizer_stopSession(_sessionHandler);
                    VoiceDistingAPI.recognizer_destroySession(_sessionHandler);
                }
                catch { }
            }
            
            if (_baseHandler!=IntPtr.Zero)
            {
                try
                {
                    VoiceDistingAPI.recognizer_destroyBase(_baseHandler);
                }
                catch { }
            }
            GC.SuppressFinalize(this);
        }
        #endregion

        #region 接口

        #endregion


        
    }
}
